/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.support.v4.view;

import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;

/**
 * Helper for accessing features in {@link View} introduced after API level 4 in
 * a backwards compatible fashion.
 */
public class ViewCompat {
	/**
	 * Always allow a user to over-scroll this view, provided it is a view that
	 * can scroll.
	 */
	public static final int OVER_SCROLL_ALWAYS = 0;

	/**
	 * Allow a user to over-scroll this view only if the content is large enough
	 * to meaningfully scroll, provided it is a view that can scroll.
	 */
	public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1;

	/**
	 * Never allow a user to over-scroll this view.
	 */
	public static final int OVER_SCROLL_NEVER = 2;

	interface ViewCompatImpl {
		public boolean canScrollHorizontally(View v, int direction);

		public boolean canScrollVertically(View v, int direction);

		public int getOverScrollMode(View v);

		public void setOverScrollMode(View v, int mode);

		public void onInitializeAccessibilityEvent(View v, AccessibilityEvent event);

		public void onPopulateAccessibilityEvent(View v, AccessibilityEvent event);

		public void onInitializeAccessibilityNodeInfo(View v, AccessibilityNodeInfoCompat info);

		public void setAccessibilityDelegate(View v, AccessibilityDelegateCompat delegate);
	}

	static class BaseViewCompatImpl implements ViewCompatImpl {
		public boolean canScrollHorizontally(View v, int direction) {
			return false;
		}

		public boolean canScrollVertically(View v, int direction) {
			return false;
		}

		public int getOverScrollMode(View v) {
			return OVER_SCROLL_NEVER;
		}

		public void setOverScrollMode(View v, int mode) {
			// Do nothing; API doesn't exist
		}

		public void setAccessibilityDelegate(View v, AccessibilityDelegateCompat delegate) {
			// Do nothing; API doesn't exist
		}

		public void onPopulateAccessibilityEvent(View v, AccessibilityEvent event) {
			// Do nothing; API doesn't exist
		}

		public void onInitializeAccessibilityEvent(View v, AccessibilityEvent event) {
			// Do nothing; API doesn't exist
		}

		public void onInitializeAccessibilityNodeInfo(View v, AccessibilityNodeInfoCompat info) {
			// Do nothing; API doesn't exist
		}
	}

	static class GBViewCompatImpl extends BaseViewCompatImpl {
		@Override
		public int getOverScrollMode(View v) {
			return ViewCompatGingerbread.getOverScrollMode(v);
		}

		@Override
		public void setOverScrollMode(View v, int mode) {
			ViewCompatGingerbread.setOverScrollMode(v, mode);
		}
	}

	/*
	 * static class ICSViewCompatImpl extends GBViewCompatImpl {
	 * 
	 * @Override public boolean canScrollHorizontally(View v, int direction) {
	 * return ViewCompatICS.canScrollHorizontally(v, direction); }
	 * 
	 * @Override public boolean canScrollVertically(View v, int direction) {
	 * return ViewCompatICS.canScrollVertically(v, direction); }
	 * 
	 * @Override public void onPopulateAccessibilityEvent(View v,
	 * AccessibilityEvent event) { ViewCompatICS.onPopulateAccessibilityEvent(v,
	 * event); }
	 * 
	 * @Override public void onInitializeAccessibilityEvent(View v,
	 * AccessibilityEvent event) {
	 * ViewCompatICS.onInitializeAccessibilityEvent(v, event); }
	 * 
	 * @Override public void onInitializeAccessibilityNodeInfo(View v,
	 * AccessibilityNodeInfoCompat info) {
	 * ViewCompatICS.onInitializeAccessibilityNodeInfo(v, info.getImpl()); }
	 * 
	 * @Override public void setAccessibilityDelegate(View v,
	 * AccessibilityDelegateCompat delegate) {
	 * ViewCompatICS.setAccessibilityDelegate(v, delegate.getBridge()); } }
	 */
	static final ViewCompatImpl IMPL;
	static {
		final int version = android.os.Build.VERSION.SDK_INT;
		/*
		 * if (version >= 14) { IMPL = new ICSViewCompatImpl(); } else
		 */if (version >= 9) {
			IMPL = new GBViewCompatImpl();
		} else {
			IMPL = new BaseViewCompatImpl();
		}
	}

	/**
	 * Check if this view can be scrolled horizontally in a certain direction.
	 * 
	 * @param v
	 *            The View against which to invoke the method.
	 * @param direction
	 *            Negative to check scrolling left, positive to check scrolling
	 *            right.
	 * @return true if this view can be scrolled in the specified direction,
	 *         false otherwise.
	 */
	public static boolean canScrollHorizontally(View v, int direction) {
		return IMPL.canScrollHorizontally(v, direction);
	}

	/**
	 * Check if this view can be scrolled vertically in a certain direction.
	 * 
	 * @param v
	 *            The View against which to invoke the method.
	 * @param direction
	 *            Negative to check scrolling up, positive to check scrolling
	 *            down.
	 * @return true if this view can be scrolled in the specified direction,
	 *         false otherwise.
	 */
	public static boolean canScrollVertically(View v, int direction) {
		return IMPL.canScrollVertically(v, direction);
	}

	/**
	 * Returns the over-scroll mode for this view. The result will be one of
	 * {@link #OVER_SCROLL_ALWAYS} (default),
	 * {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} (allow over-scrolling only if the
	 * view content is larger than the container), or {@link #OVER_SCROLL_NEVER}
	 * .
	 * 
	 * @param v
	 *            The View against which to invoke the method.
	 * @return This view's over-scroll mode.
	 */
	public static int getOverScrollMode(View v) {
		return IMPL.getOverScrollMode(v);
	}

	/**
	 * Set the over-scroll mode for this view. Valid over-scroll modes are
	 * {@link #OVER_SCROLL_ALWAYS} (default),
	 * {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} (allow over-scrolling only if the
	 * view content is larger than the container), or {@link #OVER_SCROLL_NEVER}
	 * .
	 * 
	 * Setting the over-scroll mode of a view will have an effect only if the
	 * view is capable of scrolling.
	 * 
	 * @param v
	 *            The View against which to invoke the method.
	 * @param overScrollMode
	 *            The new over-scroll mode for this view.
	 */
	public static void setOverScrollMode(View v, int overScrollMode) {
		IMPL.setOverScrollMode(v, overScrollMode);
	}

	/**
	 * Called from
	 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)}
	 * giving a chance to this View to populate the accessibility event with its
	 * text content. While this method is free to modify event attributes other
	 * than text content, doing so should normally be performed in
	 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent)}.
	 * <p>
	 * Example: Adding formatted date string to an accessibility event in
	 * addition to the text added by the super implementation:
	 * 
	 * <pre>
	 * public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
	 * 	super.onPopulateAccessibilityEvent(event);
	 * 	final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY;
	 * 	String selectedDateUtterance = DateUtils.formatDateTime(mContext, mCurrentDate.getTimeInMillis(), flags);
	 * 	event.getText().add(selectedDateUtterance);
	 * }
	 * </pre>
	 * <p>
	 * If an {@link android.view.View.AccessibilityDelegate} has been specified
	 * via calling
	 * {@link View#setAccessibilityDelegate(android.view.View.AccessibilityDelegate)}
	 * its
	 * {@link android.view.View.AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)}
	 * is responsible for handling this call.
	 * </p>
	 * <p class="note">
	 * <strong>Note:</strong> Always call the super implementation before adding
	 * information to the event, in case the default implementation has basic
	 * information to add.
	 * </p>
	 * 
	 * @param v
	 *            The View against which to invoke the method.
	 * @param event
	 *            The accessibility event which to populate.
	 * 
	 * @see View#sendAccessibilityEvent(int)
	 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
	 */
	public static void onPopulateAccessibilityEvent(View v, AccessibilityEvent event) {
		IMPL.onPopulateAccessibilityEvent(v, event);
	}

	/**
	 * Initializes an {@link AccessibilityEvent} with information about this
	 * View which is the event source. In other words, the source of an
	 * accessibility event is the view whose state change triggered firing the
	 * event.
	 * <p>
	 * Example: Setting the password property of an event in addition to
	 * properties set by the super implementation:
	 * 
	 * <pre>
	 * public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
	 * 	super.onInitializeAccessibilityEvent(event);
	 * 	event.setPassword(true);
	 * }
	 * </pre>
	 * <p>
	 * If an {@link android.view.View.AccessibilityDelegate} has been specified
	 * via calling
	 * {@link View#setAccessibilityDelegate(android.view.View.AccessibilityDelegate)}
	 * its
	 * {@link android.view.View.AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)}
	 * is responsible for handling this call.
	 * </p>
	 * <p class="note">
	 * <strong>Note:</strong> Always call the super implementation before adding
	 * information to the event, in case the default implementation has basic
	 * information to add.
	 * </p>
	 * 
	 * @param v
	 *            The View against which to invoke the method.
	 * @param event
	 *            The event to initialize.
	 * 
	 * @see View#sendAccessibilityEvent(int)
	 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
	 */
	public static void onInitializeAccessibilityEvent(View v, AccessibilityEvent event) {
		IMPL.onInitializeAccessibilityEvent(v, event);
	}

	/**
	 * Initializes an {@link android.view.accessibility.AccessibilityNodeInfo}
	 * with information about this view. The base implementation sets:
	 * <ul>
	 * <li>
	 * {@link android.view.accessibility.AccessibilityNodeInfo#setParent(View)},
	 * </li>
	 * <li>
	 * {@link android.view.accessibility.AccessibilityNodeInfo#setBoundsInParent(Rect)}
	 * ,</li>
	 * <li>
	 * {@link android.view.accessibility.AccessibilityNodeInfo#setBoundsInScreen(Rect)}
	 * ,</li>
	 * <li>
	 * {@link android.view.accessibility.AccessibilityNodeInfo#setPackageName(CharSequence)}
	 * ,</li>
	 * <li>
	 * {@link android.view.accessibility.AccessibilityNodeInfo#setClassName(CharSequence)}
	 * ,</li>
	 * <li>
	 * {@link android.view.accessibility.AccessibilityNodeInfo#setContentDescription(CharSequence)}
	 * ,</li>
	 * <li>
	 * {@link android.view.accessibility.AccessibilityNodeInfo#setEnabled(boolean)}
	 * ,</li>
	 * <li>
	 * {@link android.view.accessibility.AccessibilityNodeInfo#setClickable(boolean)}
	 * ,</li>
	 * <li>
	 * {@link android.view.accessibility.AccessibilityNodeInfo#setFocusable(boolean)}
	 * ,</li>
	 * <li>
	 * {@link android.view.accessibility.AccessibilityNodeInfo#setFocused(boolean)}
	 * ,</li>
	 * <li>
	 * {@link android.view.accessibility.AccessibilityNodeInfo#setLongClickable(boolean)}
	 * ,</li>
	 * <li>
	 * {@link android.view.accessibility.AccessibilityNodeInfo#setSelected(boolean)}
	 * ,</li>
	 * </ul>
	 * <p>
	 * Subclasses should override this method, call the super implementation,
	 * and set additional attributes.
	 * </p>
	 * <p>
	 * If an {@link android.view.View.AccessibilityDelegate} has been specified
	 * via calling
	 * {@link View#setAccessibilityDelegate(android.view.View.AccessibilityDelegate)}
	 * its
	 * {@link android.view.View.AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, android.view.accessibility.AccessibilityNodeInfo)}
	 * is responsible for handling this call.
	 * </p>
	 * 
	 * @param v
	 *            The View against which to invoke the method.
	 * @param info
	 *            The instance to initialize.
	 */
	public static void onInitializeAccessibilityNodeInfo(View v, AccessibilityNodeInfoCompat info) {
		IMPL.onInitializeAccessibilityNodeInfo(v, info);
	}

	/**
	 * Sets a delegate for implementing accessibility support via compositon as
	 * opposed to inheritance. The delegate's primary use is for implementing
	 * backwards compatible widgets. For more details see
	 * {@link android.view.View.AccessibilityDelegate}.
	 * 
	 * @param v
	 *            The View against which to invoke the method.
	 * @param delegate
	 *            The delegate instance.
	 * 
	 * @see android.view.View.AccessibilityDelegate
	 */
	public static void setAccessibilityDelegate(View v, AccessibilityDelegateCompat delegate) {
		IMPL.setAccessibilityDelegate(v, delegate);
	}
}
